home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 4 / QRZ Ham Radio Callsign Database - Volume 4.iso / files / tcpip / amiga / asrc29p.lha / smtpserv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-29  |  24.5 KB  |  979 lines

  1. /* SMTP Server state machine - see RFC 821
  2.  *  enhanced 4/88 Dave Trulli nn2z
  3.  */
  4. #define   EOM   0x7f
  5. #include <stdio.h>
  6. #include <time.h>
  7. #if   defined(__STDC__) || defined(__TURBOC__)
  8. #include <stdarg.h>
  9. #endif
  10. #include <ctype.h>
  11. #include <setjmp.h>
  12. #include "global.h"
  13. #include "config.h"
  14. #include "mbuf.h"
  15. #include "cmdparse.h"
  16. #include "socket.h"
  17. #include "iface.h"
  18. #include "proc.h"
  19. #include "smtp.h"
  20. #include "commands.h"
  21. #include "dirutil.h"
  22. #include "mailbox.h"
  23. #include "netuser.h"
  24. #include "ax25.h"
  25. #include <dos.h>
  26. #include <stdlib.h>
  27. #include <ios1.h>
  28. #include <proto/dos.h>
  29. #include "bm.h"
  30.  
  31. char *Days[7] = { "Sun","Mon","Tue","Wed","Thu","Fri","Sat" };
  32. char *Months[12] = { "Jan","Feb","Mar","Apr","May","Jun",
  33.       "Jul","Aug","Sep","Oct","Nov","Dec" };
  34.  
  35. static struct list *expandalias __ARGS((struct list **head,char *user));
  36. static int  getmsgtxt __ARGS((struct smtpsv *mp));
  37. static struct smtpsv *mail_create __ARGS((void));
  38. static void mail_clean __ARGS((struct smtpsv *mp));
  39. static int mailit __ARGS((FILE *data,char *from,struct list *tolist));
  40. static int router_queue __ARGS((FILE *data,char *from,struct list *to));
  41. static void smtpserv __ARGS((int s,void *unused,void *p));
  42.  
  43. int dosmtpaccept __ARGS((int argc,char *argv[],void *p));
  44. int dosmtpreject __ARGS((int argc,char *argv[],void *p));
  45.  
  46. static struct list *appendlist __ARGS((struct list **head,char *val,int type));
  47.  
  48. /* Command table */
  49. static char *commands[] = {
  50.    "helo",
  51. #define   HELO_CMD   0
  52.    "noop",
  53. #define   NOOP_CMD   1
  54.    "mail from:",
  55. #define   MAIL_CMD   2
  56.    "quit",
  57. #define   QUIT_CMD   3
  58.    "rcpt to:",
  59. #define   RCPT_CMD   4
  60.    "help",
  61. #define   HELP_CMD   5
  62.    "data",
  63. #define   DATA_CMD   6
  64.    "rset",
  65. #define   RSET_CMD   7
  66.    "expn",
  67. #define EXPN_CMD   8
  68.    NULLCHAR
  69. };
  70.  
  71. /* Reply messages */
  72.  
  73. static char help[]     = "214-Commands:\n214-HELO NOOP MAIL QUIT RCPT HELP DATA RSET EXPN\n214 End\n";
  74. static char banner[]   = "220 %s SMTP Ready\n";
  75. static char closing[]  = "221 Closing\n";
  76. static char ok[]       = "250 Ok\n";
  77. static char reset[]    = "250 Reset state\n";
  78. static char sent[]     = "250 Sent\n";
  79. static char ourname[]  = "250 %s, Share and Enjoy!\n";
  80.  
  81. static char enter[]    = "354 Enter mail, end with .\n";
  82.  
  83. static char lowmem[]   = "421 System overloaded, try again later\n";
  84. static char ioerr[]    = "452 Temp file write error\n";
  85.  
  86. static char badcmd[]   = "500 Command unrecognized\n";
  87. static char syntax[]   = "501 Syntax error\n";
  88. static char needrcpt[] = "503 Need RCPT (recipient)\n";
  89. static char unknown[]  = "550 <%s> address unknown\n";
  90. static char noalias[]  = "550 No alias for <%s>\n";
  91. static char reject[]   = "550-Rejected, Authorisation required\n550 Please mail the Postmaster of this system for further help\n";
  92.  
  93. static int Ssmtp = -1; /* prototype socket for service */
  94. extern int AMSound;
  95.  
  96. /* SMTP Reject structure */
  97. struct lr {
  98.    struct lr *prev;
  99.    struct lr *next;
  100.    char addr[AXALEN];
  101. };
  102.  
  103. struct lr *Lr;
  104.  
  105. int dosmtpreject(argc,argv,p)
  106. int argc;
  107. char *argv[];
  108. void *p;
  109. {
  110.    register struct lr *lp;
  111.  
  112.    if (argc < 2) {
  113.       tprintf("smtp reject list: ");
  114.       if(Lr != NULLLQ)
  115.          for(lp = Lr;lp != NULLLQ;lp = lp->next)
  116.             tprintf(" %s",lp->addr);
  117.       else
  118.          tprintf(" Empty");
  119.       tprintf("\n");
  120.    } else {
  121.       lp = (struct lr *)callocw(1,sizeof(struct lr));
  122.       memcpy(lp->addr,argv[1],AXALEN);
  123.       lp->next = Lr;
  124.       if(lp->next != NULLLQ)
  125.          lp->next->prev = lp;
  126.       Lr = lp;
  127.       tprintf("'%s' added to reject list\n",argv[1]);
  128.    }
  129.    return 0;
  130. }
  131.  
  132. int dosmtpaccept(argc,argv,p)
  133. int argc;
  134. char *argv[];
  135. void *p;
  136. {
  137.    register struct lr *lp;
  138.  
  139.    if (argc < 2) 
  140.       tprintf("string missing!\n");
  141.    else {
  142.       for(lp = Lr;lp != NULLLQ;lp = lp->next)
  143.          if(strstr(argv[1],lp->addr))
  144.             break;
  145.  
  146.       if(lp == NULLLQ) {
  147.          tprintf("Not found\n");
  148.          return 1;
  149.       }
  150.  
  151.       if(lp->prev != NULLLQ)
  152.          lp->prev->next = lp->next;
  153.       else
  154.          Lr = lp->next;
  155.       if(lp->next != NULLLQ)
  156.          lp->next->prev = lp->prev;
  157.  
  158.       tprintf("'%s' removed from reject list\n",argv[1]);
  159.    }
  160.    return 0;
  161. }
  162.  
  163. /* Start up SMTP receiver service */
  164. int smtp1(argc,argv,p)
  165. int argc;
  166. char *argv[];
  167. void *p;
  168. {
  169.    struct sockaddr_in lsocket;
  170.    int s;
  171.  
  172.    if(Ssmtp != -1){
  173.       return 0;
  174.    }
  175.    psignal(Curproc,0);   /* Don't keep the parser waiting */
  176.    chname(Curproc,"SMTP listener");
  177.  
  178.    lsocket.sin_family = AF_INET;
  179.    lsocket.sin_addr.s_addr = INADDR_ANY;
  180.    if(argc < 2)
  181.       lsocket.sin_port = IPPORT_SMTP;
  182.    else
  183.       lsocket.sin_port = atoi(argv[1]);
  184.  
  185.    Ssmtp = socket(AF_INET,SOCK_STREAM,0);
  186.    bind(Ssmtp,(char *)&lsocket,sizeof(lsocket));
  187.    listen(Ssmtp,1);
  188.    for(;;){
  189.       if((s = accept(Ssmtp,NULLCHAR,(int *)NULL)) == -1)
  190.          break;   /* Service is shutting down */
  191.  
  192.       if(availmem() < Memthresh){
  193.          usprintf(s,lowmem);
  194.          shutdown(s,1);
  195.       } else {
  196.          /* Spawn a server */
  197.          newproc("SMTP server",2048,smtpserv,s,NULL,NULL);
  198.       }
  199.    }
  200.    return 0;
  201. }
  202.  
  203. /* Shutdown SMTP service (existing connections are allowed to finish) */
  204. int smtp0(argc,argv,p)
  205. int argc;
  206. char *argv[];
  207. void *p;
  208. {
  209.    close_s(Ssmtp);
  210.    Ssmtp = -1;
  211.    return 0;
  212. }
  213.  
  214. static void smtpserv(s,unused,p)
  215. int s;
  216. void *unused;
  217. void *p;
  218. {
  219.    register struct lr *lp;
  220.    struct smtpsv *mp;
  221.    char **cmdp,buf[LINELEN],*arg,*cp,*cmd,*newaddr;
  222.    struct list *ap,*list;
  223.    int cnt;
  224.    char address_type;
  225.  
  226.    sockowner(s,Curproc);      /* We own it now */
  227.    mainlog(s,"open SMTP");
  228.  
  229.    if((mp = mail_create()) == NULLSMTPSV){
  230.       printf(Nospace);
  231.       mainlog(s,"close SMTP - no space");
  232.       close_s(s);
  233.       return;
  234.    }
  235.    mp->s = s;
  236.  
  237.    (void) usprintf(s,banner,Hostname);
  238.  
  239. loop:   if ((cnt = recvline(s,buf,sizeof(buf))) == -1) {
  240.       /* He closed on us */
  241.       goto quit;
  242.    }
  243.    if(cnt < 4){
  244.       /* Can't be a legal command */
  245.       usprintf(mp->s,badcmd);
  246.       goto loop;
  247.    }   
  248.    rip(buf);
  249.    cmd = buf;
  250.  
  251.    /* Translate entire buffer to lower case */
  252.    for(cp = cmd;*cp != '\0';cp++)
  253.       *cp = tolower(*cp);
  254.  
  255.    /* Find command in table; if not present, return syntax error */
  256.    for(cmdp = commands;*cmdp != NULLCHAR;cmdp++)
  257.       if(strncmp(*cmdp,cmd,strlen(*cmdp)) == 0)
  258.          break;
  259.    if(*cmdp == NULLCHAR){
  260.       (void) usprintf(mp->s,badcmd);
  261.       goto loop;
  262.    }
  263.    arg = &cmd[strlen(*cmdp)];
  264.    /* Skip spaces after command */
  265.    while(*arg == ' ')
  266.       arg++;
  267.    /* Execute specific command */
  268.    switch(cmdp-commands) {
  269.    case HELO_CMD:
  270.       free(mp->system);
  271.       mp->system = strdup(arg);
  272.       (void) usprintf(mp->s,ourname,Hostname);
  273.       break;
  274.    case NOOP_CMD:
  275.       (void) usprintf(mp->s,ok);
  276.       break;
  277.    case MAIL_CMD:
  278.       if((cp = getname(arg)) == NULLCHAR){
  279.          (void) usprintf(mp->s,syntax);
  280.          break;
  281.       }
  282.       free(mp->from);
  283.       mp->from = strdup(cp);
  284.       for(lp = Lr;lp != NULLLQ;lp = lp->next)
  285.          if(strstr(mp->from,lp->addr)) {
  286.             mainlog(-1,"SMTP rejected mail from '%s'",mp->from);
  287.             printf("\x1b[32mRejected Mail From '\x1b[33m%s\x1b[32m'\x1b[0m\n",mp->from);
  288.             (void) usprintf(mp->s,reject);
  289.             break;
  290.          }
  291.       (void) usprintf(mp->s,ok);
  292.       break;
  293.    case QUIT_CMD:
  294.       (void) usprintf(mp->s,closing);
  295.       goto quit;
  296.    case RCPT_CMD:   /* Specify recipient */
  297.       if((cp = getname(arg)) == NULLCHAR){
  298.          (void) usprintf(mp->s,syntax);
  299.          break;
  300.       }
  301.  
  302.       /* rewrite address if possible */
  303.       if((newaddr = rewrite_address(cp)) != NULLCHAR)
  304.          if(strcmp(cp,newaddr) != 0)
  305.             cp = newaddr;
  306.          else
  307.             free(newaddr);
  308.  
  309.       /* check if address is ok */
  310.       if ((address_type = validate_address(cp)) == BADADDR) {
  311.          (void) usprintf(mp->s,unknown,cp);
  312.          break;
  313.       }
  314.       /* if a local address check for an alias */
  315.       if (address_type == LOCAL)
  316.          expandalias(&mp->to, cp);
  317.       else
  318.          /* a remote address is added to the list */
  319.          addlist(&mp->to, cp, address_type);
  320.  
  321.       (void) usprintf(mp->s,ok);
  322.       break;
  323.    case HELP_CMD:
  324.       (void) usprintf(mp->s,help);
  325.       break;
  326.    case DATA_CMD:
  327.       if(mp->to == NULLLIST)
  328.          (void) usprintf(mp->s,needrcpt);
  329.       else if ((mp->data = tmpfile()) == NULLFILE)
  330.          (void) usprintf(mp->s,ioerr);
  331.        else
  332.          getmsgtxt(mp);
  333.       break;
  334.    case RSET_CMD:
  335.       del_list(mp->to);
  336.       mp->to = NULLLIST;
  337.       (void) usprintf(mp->s,reset);
  338.       break;
  339.    case EXPN_CMD:
  340.       if (*arg == '\0') {
  341.          (void) usprintf(mp->s,syntax);
  342.          break;
  343.       }
  344.  
  345.       list = NULLLIST;
  346.       /* rewrite address if possible */
  347.       if((newaddr = rewrite_address(arg)) != NULLCHAR)
  348.          if(strcmp(newaddr,arg) == 0) {
  349.             free(newaddr);
  350.             newaddr = NULLCHAR;
  351.          }
  352.          else {
  353.             strcpy(buf,newaddr);
  354.             arg = buf;
  355.          }
  356.       list = NULLLIST;
  357.       expandalias(&list,arg);
  358.       if (strcmp(list->val,arg) == 0 && list->next == NULLLIST)
  359.          if(newaddr == NULLCHAR) {
  360.             (void) usprintf(mp->s,noalias,arg);
  361.             del_list(list);
  362.             break;
  363.          }
  364.       ap = list;
  365.       while (ap->next != NULLLIST) {
  366.          (void) usprintf(mp->s,"250-%s\n",ap->val);
  367.          ap = ap->next;
  368.       }
  369.       usprintf(mp->s,"250 %s\n",ap->val);
  370.       del_list(list);
  371.       free(newaddr);
  372.       break;
  373.    }
  374.    goto loop;
  375.  
  376. quit:
  377.    mainlog(mp->s,"close SMTP");
  378.    close_s(mp->s);
  379.    mail_clean(mp);
  380. }
  381.  
  382. /* read the message text */
  383. static int getmsgtxt(mp)
  384. struct smtpsv *mp;
  385. {
  386.    char buf[LINELEN];
  387.    register char *p = buf;
  388.    long t;
  389.  
  390.    /* Add timestamp; ptime adds newline */
  391.    time(&t);
  392.    fprintf(mp->data,"Received: ");
  393.    if(mp->system != NULLCHAR)
  394.       fprintf(mp->data,"from %s ",mp->system);
  395.    fprintf(mp->data,"by %s with SMTP\n\tid AA%ld ; %s",
  396.          Hostname, get_msgid(), ptime(&t));
  397.    if(ferror(mp->data)){
  398.       (void) usprintf(mp->s,ioerr);
  399.       return 1;
  400.    } else {
  401.       (void) usprintf(mp->s,enter);
  402.    }
  403.    while(1) {
  404.       if(recvline(mp->s,p,sizeof(buf)) == -1){
  405.          return 1;
  406.       }
  407.       rip(p);
  408.       /* check for end of message ie a . or escaped .. */
  409.       if (*p == '.') {
  410.          if (*++p == '\0') {
  411.             /* Also sends appropriate response */
  412.             if (mailit(mp->data,mp->from,mp->to) != 0)
  413.                (void) usprintf(mp->s,ioerr);
  414.             else
  415.                (void) usprintf(mp->s,sent);
  416.             fclose(mp->data);
  417.             mp->data = NULLFILE;
  418.             del_list(mp->to);
  419.             mp->to = NULLLIST;
  420.             return 0;
  421.          } else if (!(*p == '.' && *(p+1) == '\0'))
  422.             p--;
  423.       }
  424.       /* for UNIX mail compatiblity */
  425.       if (strncmp(p,"From ",5) == 0)
  426.          (void) putc('>',mp->data);
  427.  
  428.       /* Append to data file */
  429.       if(fprintf(mp->data,"%s\n",p) < 0) {
  430.          (void) usprintf(mp->s,ioerr);
  431.          return 1;
  432.       }
  433.  
  434.    }
  435. }
  436.  
  437. /* Create control block, initialize */
  438. static struct smtpsv *mail_create()
  439. {
  440.    register struct smtpsv *mp;
  441.  
  442.    mp = (struct smtpsv *)callocw(1,sizeof(struct smtpsv));
  443.    mp->from = strdup("");   /* Default to null From address */
  444.    return mp;
  445. }
  446.  
  447. /* Free resources, delete control block */
  448. static void mail_clean(mp)
  449. register struct smtpsv *mp;
  450. {
  451.    if (mp == NULLSMTPSV)
  452.       return;
  453.    free(mp->system);
  454.    free(mp->from);
  455.    if(mp->data != NULLFILE)
  456.       fclose(mp->data);
  457.    del_list(mp->to);
  458.    free((char *)mp);
  459. }
  460.  
  461.  
  462. /* Given a string of the form <user@host>, extract the part inside the
  463.  * brackets and return a pointer to it.
  464.  */
  465. char *getname(cp)
  466. register char *cp;
  467. {
  468.    register char *cp1;
  469.  
  470.    if ((cp = strchr(cp,'<')) == NULLCHAR)
  471.       return NULLCHAR;
  472.    cp++;   /* cp -> first char of name */
  473.    if ((cp1 = strchr(cp,'>')) == NULLCHAR)
  474.       return NULLCHAR;
  475.    *cp1 = '\0';
  476.    return cp;
  477. }
  478.  
  479. /* General mailit function. It takes a list of addresses which have already
  480. ** been verified and expanded for aliases. Base on the current mode the message
  481. ** is place in an mbox, the outbound smtp queue or the rqueue interface
  482. */
  483. static int mailit(data,from,tolist)
  484. FILE *data;
  485. char *from;
  486. struct list *tolist;
  487. {
  488.    extern int DiggerLock;
  489.    static char MBid[] = "Digger";
  490.    int DiggerShouldRun = 0;
  491.  
  492.    struct list *ap, *dlist = NULLLIST;
  493.    register FILE *fp;
  494.    char   mailbox[50], *cp, *desthost, *qhost, command[40];
  495.    int   c, fail = 0, index;
  496.    time_t   t;
  497.  
  498.    if ((Smtpmode & QUEUE) != 0)
  499.       return(router_queue(data,from,tolist));
  500.  
  501.    do {
  502.       qhost = NULLCHAR;
  503.       for(ap = tolist;ap != NULLLIST;ap = ap->next)
  504.          if (ap->type == DOMAIN) {
  505.             if ((desthost = strrchr(ap->val,'@')) != NULLCHAR)
  506.                desthost++;
  507.             else
  508.                desthost = Hostname;
  509.             if(qhost == NULLCHAR)
  510.                   qhost = desthost;
  511.             if(stricmp(qhost,desthost) == 0) {
  512.                ap->type = BADADDR;
  513.                addlist(&dlist,ap->val,0);
  514.             }
  515.          }
  516.       if(qhost != NULLCHAR) {
  517.          rewind(data);
  518.          queuejob(data,qhost,dlist,from);
  519.          del_list(dlist);
  520.          dlist = NULLLIST;
  521.       }
  522.    } while(qhost != NULLCHAR);
  523.  
  524.    for(ap = tolist,index = 0;ap != NULLLIST;ap = ap->next, index++) {
  525.       if(ap->type != LOCAL) {
  526.          ap->type = DOMAIN;
  527.          continue;
  528.       }
  529.       rewind(data);
  530.       /* strip off host name of LOCAL addresses */
  531.       if ((cp = strchr(ap->val,'@')) != NULLCHAR)
  532.          *cp = '\0';
  533.  
  534.       /* truncate long user names */
  535.       if (strlen(ap->val) > MBOXLEN)
  536.          ap->val[MBOXLEN] = '\0';
  537.  
  538.       /* if mail file is busy save it in our smtp queue
  539.        * and let the smtp daemon try later.
  540.        */
  541.       if (mlock(Mailspool,ap->val)) {
  542.          addlist(&dlist,ap->val,0);
  543.          fail = queuejob(data,Hostname,dlist,from);
  544.          del_list(dlist);
  545.          dlist = NULLLIST;
  546.       } else {
  547.          char buf[LINELEN];
  548.          int tocnt = 0;
  549.          sprintf(mailbox,"%s/%s.txt",Mailspool,ap->val);
  550.          if((fp = fopen(mailbox,APPEND_TEXT)) != NULLFILE) {
  551.             time(&t);
  552.             fprintf(fp,"From %s %s",from,ctime(&t));
  553.             desthost = NULLCHAR;
  554.             while(fgets(buf,sizeof(buf),data) != NULLCHAR) {
  555.                if(buf[0] == '\n') {
  556.                   if(tocnt == 0)
  557.                      fprintf(fp,"%s%s\n",Hdrs[APPARTO],ap->val);
  558.                   fputc('\n',fp);
  559.                   break;
  560.                }
  561.                if(index && htype(buf) == MSGID) {
  562.                   fprintf(fp,"%s<%ld@%s>\n",
  563.                              Hdrs[MSGID], get_msgid(), Hostname);
  564.                } else
  565.                   fputs(buf,fp);
  566.                rip(buf);
  567.                switch(htype(buf)) {
  568.                case TO:
  569.                case CC:
  570.                   ++tocnt;
  571.                   break;
  572.                case RRECEIPT:
  573.                   if((cp = getaddress(buf,0)) != NULLCHAR) {
  574.                      free(desthost);
  575.                      desthost = strdup(cp);
  576.                   }
  577.                   break;
  578.                }
  579.             }
  580.             while((c = fread(buf,1,sizeof(buf),data)) > 0)
  581.                if(fwrite(buf,1,c,fp) != c)
  582.                   break;
  583.             if(ferror(fp))
  584.                fail = 1;
  585.             else
  586.                fprintf(fp,"\n");
  587.  
  588.    /* If this is for the Digger, put a special mark
  589.       between messages to make them easier to find. */
  590.                if (strnicmp(ap->val, MBid, strlen(MBid)) == 0) {
  591.                   putc(EOM,fp);
  592.                   putc('\n',fp);
  593.                }
  594.  
  595.             /* Leave a line between msgs */
  596.             fclose(fp);
  597.          }
  598.  
  599.          if (strnicmp(ap->val, MBid, strlen(MBid))) {
  600.             printf("\x1b[32mNew Mail for '\x1b[33m%s\x1b[32m' from '\x1b[33m%s\x1b[32m'\x1b[0m\n",ap->val,from);
  601.             if(AMSound) {
  602.                sprintf(command, "SAY -n -p77 -s250 New Mail");
  603.                Execute(command, 0, 0);
  604.             }
  605.          } else {
  606.             printf("\a\x1b[32mDigger Request From '\x1b[33m%s\x1b[32m'\x1b[0m\n",from);
  607.             DiggerShouldRun++;
  608.          }
  609.  
  610.       };
  611.       (void) rmlock(Mailspool,ap->val);
  612.       if (fail)
  613.          break;
  614.       mainlog(-1,"deliver: To: %s From: %s",ap->val,from);
  615.    }
  616.  
  617.    /* If the Digger got mail, start up the task again... */
  618.    if (DiggerShouldRun)
  619.       psignal(&DiggerLock,1);
  620.  
  621.    return fail;
  622. }
  623.  
  624. /* Return Date/Time in Arpanet format in passed string */
  625. char *ptime(t)
  626. long *t;
  627. {
  628.    /* Print out the time and date field as
  629.     *      "DAY day MONTH year hh:mm:ss ZONE"
  630.     */
  631.    register struct tm *ltm;
  632.    static char tz[4];
  633.    static char str[40];
  634.    char *p, *getenv();
  635.    /* Read the system time */
  636.    ltm = localtime(t);
  637.  
  638.    if (*tz == '\0')
  639.       if ((p = getenv("TZ")) == NULL)
  640.          strcpy(tz,"GMT");
  641.       else
  642.          strncpy(tz,p,3);
  643.  
  644.    /* rfc 822 format */
  645.    sprintf(str,"%s, %.2d %s %02d %02d:%02d:%02d %.3s\n",
  646.       Days[ltm->tm_wday],
  647.       ltm->tm_mday,
  648.       Months[ltm->tm_mon],
  649.       ltm->tm_year,
  650.       ltm->tm_hour,
  651.       ltm->tm_min,
  652.       ltm->tm_sec,
  653.       tz);
  654.    return(str);
  655. }
  656.  
  657. long get_msgid()
  658. {
  659.    char sfilename[LINELEN];
  660.    char s[20];
  661.    register long sequence = 0;
  662.    FILE *sfile;
  663.  
  664.    sprintf(sfilename,"%s/sequence.seq",Mailqdir);
  665.    sfile = fopen(sfilename,READ_TEXT);
  666.  
  667.    /* if sequence file exists, get the value, otherwise set it */
  668.    if (sfile != NULL) {
  669.       (void) fgets(s,sizeof(s),sfile);
  670.       sequence = atol(s);
  671.    /* Keep it in range of and 8 digit number to use for dos name prefix. */
  672.       if (sequence < 0L || sequence > 99999999L )
  673.          sequence = 0;
  674.       fclose(sfile);
  675.    }
  676.  
  677.    /* increment sequence number, and write to sequence file */
  678.    sfile = fopen(sfilename,WRITE_TEXT);
  679.    fprintf(sfile,"%ld",++sequence);
  680.    fclose(sfile);
  681.    return sequence;
  682. }
  683.  
  684. #ifdef   MSDOS
  685. /* Illegal characters in a DOS filename */
  686. static char baddoschars[] = "\"[]:|<>+=;,";
  687. #endif
  688.  
  689. /* test if mail address is valid */
  690. int validate_address(s)
  691. char *s;
  692. {
  693.    char *cp;
  694.    int32 addr;
  695.  
  696.    /* if address has @ in it the check dest address */
  697.    if ((cp = strrchr(s,'@')) != NULLCHAR) {
  698.       cp++;
  699.       /* 1st check if its our hostname
  700.       * if not then check the hosts file and see
  701.       * if we can resolve ther address to a know site
  702.       * or one of our aliases
  703.       */
  704.       if (strcmp(cp,Hostname) != 0) {
  705.          if ((addr = mailroute(cp)) == 0
  706.             && (Smtpmode & QUEUE) == 0)
  707.             return BADADDR;
  708.          if (ismyaddr(addr) == NULLIF)
  709.             return DOMAIN;
  710.       }
  711.       /* on a local address remove the host name part */
  712.       *--cp = '\0';
  713.    }
  714.  
  715.    /* if using an external router leave address alone */
  716.    if ((Smtpmode & QUEUE) != 0)
  717.       return LOCAL;
  718.  
  719.    /* check for the user%host hack */
  720.    if ((cp = strrchr(s,'%')) != NULLCHAR) {
  721.       *cp = '@';
  722.       cp++;
  723.       /* reroute based on host name following the % seperator */
  724.       if (mailroute(cp) == 0)
  725.          return BADADDR;
  726.       else
  727.          return DOMAIN;
  728.    }
  729. #ifdef MSDOS   /* dos file name checks */
  730.    /* Check for characters illegal in MS-DOS file names */
  731.    for(cp = baddoschars;*cp != '\0';cp++){
  732.       if(strchr(s,*cp) != NULLCHAR)
  733.          return BADADDR;   
  734.    }
  735. #endif
  736.    return LOCAL;
  737. }
  738.  
  739. /* place a mail job in the outbound queue */
  740. int queuejob(dfile,host,to,from)
  741. FILE *dfile;
  742. char *host;
  743. struct list *to;
  744. char *from;
  745. {
  746.    FILE *fp;
  747.    struct list *ap;
  748.    char tmpstring[50], prefix[9], buf[LINELEN];
  749.    register int cnt;
  750.  
  751.    sprintf(prefix,"%ld",get_msgid());
  752.    mainlog(-1,"queue job %s To: %s From: %s",prefix,to,from);
  753.    mlock(Mailqdir,prefix);
  754.    sprintf(tmpstring,"%s/%s.txt",Mailqdir,prefix);
  755.    if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE) {
  756.       (void) rmlock(Mailqdir,prefix);
  757.       return 1;
  758.    }
  759.    while((cnt = fread(buf, 1, LINELEN, dfile)) > 0)
  760.       if(fwrite(buf, 1, cnt, fp) != cnt)
  761.          break;
  762.    if(ferror(fp)){
  763.       fclose(fp);
  764.       (void) rmlock(Mailqdir,prefix);
  765.       return 1;
  766.    }
  767.    fclose(fp);
  768.    sprintf(tmpstring,"%s/%s.wrk",Mailqdir,prefix);
  769.    if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE) {
  770.       (void) rmlock(Mailqdir,prefix);
  771.       return 1;
  772.    }
  773.    fprintf(fp,"%s\n%s\n",host,from);
  774.    for(ap = to; ap != NULLLIST; ap = ap->next)
  775.       fprintf(fp,"%s\n",ap->val);
  776.    fclose(fp);
  777.    (void) rmlock(Mailqdir,prefix);
  778.    return 0;
  779. }
  780.  
  781. /* Deliver mail to the appropriate mail boxes */
  782. static int router_queue(data,from,to)
  783. FILE *data;
  784. char *from;
  785. struct list *to;
  786. {
  787.    int c;
  788.    register struct list *ap;
  789.    FILE *fp;
  790.    char tmpstring[50];
  791.    char prefix[9];
  792.  
  793.    sprintf(prefix,"%ld",get_msgid());
  794.    mlock(Routeqdir,prefix);
  795.    sprintf(tmpstring,"%s/%s.txt",Routeqdir,prefix);
  796.    if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE) {
  797.       (void) rmlock(Routeqdir,prefix);
  798.       return 1;
  799.    }
  800.    rewind(data);
  801.    while((c = getc(data)) != EOF)
  802.       if(putc(c,fp) == EOF)
  803.          break;
  804.    if(ferror(fp)){
  805.       fclose(fp);
  806.       (void) rmlock(Routeqdir,prefix);
  807.       return 1;
  808.    }
  809.    fclose(fp);
  810.    sprintf(tmpstring,"%s/%s.wrk",Routeqdir,prefix);
  811.    if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE) {
  812.       (void) rmlock(Routeqdir,prefix);
  813.       return 1;
  814.    }
  815.    fprintf(fp,"From: %s\n",from);
  816.    for(ap = to;ap != NULLLIST;ap = ap->next) {
  817.       fprintf(fp,"To: %s\n",ap->val);
  818.    }
  819.    fclose(fp);
  820.    (void) rmlock(Routeqdir,prefix);
  821.    mainlog(-1,"rqueue job %s From: %s",prefix,from);
  822.    return 0;
  823. }
  824.  
  825. /* add an element to the front of the list pointed to by head 
  826. ** return NULLLIST if out of memory.
  827. */
  828. struct list *addlist(head,val,type)
  829. struct list **head;
  830. char *val;
  831. int type;
  832. {
  833.    register struct list *tp;
  834.  
  835.    tp = (struct list *)callocw(1,sizeof(struct list));
  836.  
  837.    tp->next = NULLLIST;
  838.  
  839.    /* allocate storage for the char string */
  840.    tp->val = strdup(val);
  841.    tp->type = type;
  842.  
  843.    /* add entry to front of existing list */
  844.    if (*head == NULLLIST)
  845.       *head = tp;
  846.    else {
  847.       tp->next = *head;
  848.       *head = tp;
  849.    }
  850.    return tp;
  851. }
  852.  
  853. /*
  854. ** Similar to above, but adds new entry onto the end of the list.  Handy
  855. ** for adding a new element while currently in the middle of the list.
  856. */
  857. static struct list *appendlist(head,val,type)
  858. struct list **head;
  859. char *val;
  860. int type;
  861. {
  862.    register struct list *tp, *ptr;
  863.  
  864.    tp = (struct list *)callocw(1,sizeof(struct list));
  865.  
  866.    tp->next = NULLLIST;
  867.  
  868.    /* allocate storage for the char string */
  869.    tp->val = strdup(val);
  870.    tp->type = type;
  871.  
  872.    /*
  873.    ** Find the end of the list...
  874.    */
  875.  
  876.    if (*head == NULLLIST)
  877.       *head = tp;
  878.    else
  879.    {
  880.       ptr = *head;
  881.       while (ptr->next != NULLLIST) ptr = ptr->next;
  882.       ptr->next = tp;
  883.    }
  884.    return tp;
  885. }
  886.  
  887. #define SKIPWORD(X) while(*X && *X!=' ' && *X!='\t' && *X!='\n' && *X!= ',') X++;
  888. #define SKIPSPACE(X) while(*X ==' ' || *X =='\t' || *X =='\n' || *X == ',') X++;
  889.  
  890. /* check for and alias and expand alias into a address list */
  891. static struct list *expandalias(head, user)
  892. struct list **head;
  893. char *user;
  894. {
  895.    FILE *fp;
  896.    register char *s,*p;
  897.    int inalias;
  898.    struct list *tp;
  899.    char buf[LINELEN];
  900.  
  901.    /* no alias file found */
  902.    if ((fp = fopen(Alias, READ_TEXT)) == NULLFILE)
  903.       return addlist(head, user, LOCAL);
  904.  
  905.    inalias = 0;
  906.    while (fgets(buf,LINELEN,fp) != NULLCHAR) {
  907.       p = buf;
  908.       if ( *p == '#' || *p == '\0')
  909.          continue;
  910.       rip(p);
  911.  
  912.       /* if not in an matching entry skip continuation lines */
  913.       if (!inalias && isspace(*p))
  914.          continue;
  915.  
  916.       /* when processing an active alias check for a continuation */
  917.       if (inalias) {
  918.          if (!isspace(*p)) 
  919.             break;   /* done */
  920.       } else {
  921.          s = p;
  922.          SKIPWORD(p);
  923.          *p++ = '\0';   /* end the alias name */
  924.          if (strcmp(s,user) != 0)
  925.             continue;   /* no match go on */
  926.          inalias = 1;
  927.       }
  928.  
  929.       /* process the recipients on the alias line */
  930.       SKIPSPACE(p);
  931.       while(*p != '\0' && *p != '#') {
  932.          s = p;
  933.          SKIPWORD(p);
  934.          if (*p != '\0')
  935.             *p++ = '\0';
  936.  
  937.          /* find hostname */
  938.          if (strchr(s,'@') != NULLCHAR)
  939.             tp = addlist(head,s,DOMAIN);
  940.          else
  941.             tp = addlist(head,s,LOCAL);
  942.          SKIPSPACE(p);
  943.       }
  944.    }
  945.    (void) fclose(fp);
  946.  
  947.    if (inalias)   /* found and processed and alias. */
  948.       return tp;
  949.  
  950.    /* no alias found treat as a local address */
  951.    return addlist(head, user, LOCAL);
  952. }
  953.  
  954. /* send mail to a single user. Can be called from the ax25 mailbox or
  955. ** from the return mail function in the smtp client */
  956. int mailuser(data,from,to)
  957. FILE *data;
  958. char *from;
  959. char *to;
  960. {
  961.       int address_type, ret;
  962.       struct list *tolist = NULLLIST;
  963.  
  964.       /* check if address is ok */
  965.       if ((address_type = validate_address(to)) == BADADDR) {
  966.          return 1;
  967.       }
  968.       /* if a local address check for an alias */
  969.       if (address_type == LOCAL)
  970.          expandalias(&tolist, to);
  971.       else
  972.          /* a remote address is added to the list */
  973.          addlist(&tolist, to, address_type);
  974.       ret = mailit(data,from,tolist);
  975.       del_list(tolist);
  976.       return ret;
  977.  
  978. }
  979.